package com.wss.common.utils;

import com.wss.common.utils.toast.*;
import com.wss.common.utils.toast.style.ToastBlackStyle;
import ohos.aafwk.ability.AbilityPackage;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.window.dialog.ToastDialog;
import ohos.app.Context;
import ohos.global.systemres.ResourceTable;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ToastUtils {

    private static IToastInterceptor sInterceptor;

    private static IToastStrategy sStrategy;

    private static ToastDialog sToast;

    /**
     * 不允许外部实例化
     */
    private ToastUtils() {
    }

    /**
     * 初始化 ToastUtils，在 Application 中初始化
     *
     * @param application 应用的上下文
     */
    public static void init(AbilityPackage application) {
        init(application, new ToastBlackStyle(application));
    }

    /**
     * 初始化 ToastUtils 及样式
     *
     * @param application 应用的上下文
     * @param style       Toast样式
     */
    public static void init(AbilityPackage application, IToastStyle style) {
        checkNullPointer(application);
        // 初始化 Toast 拦截器
        if (sInterceptor == null) {
            setToastInterceptor(new ToastInterceptor());
        }

        // 初始化 Toast 显示处理器
        if (sStrategy == null) {
            setToastStrategy(new ToastStrategy());
        }

        // 初始化吐司
        if (areNotificationsEnabled(application)) {
            sToast = new BaseToast(application);
        } else {
            // 解决关闭通知栏权限后 Toast 不显示的问题
            sToast = new SupportToast(application);
        }

        // 设置 Toast 视图
//        setView(createTextView(application, style));

        // 设置 Toast 重心
//        setGravity(style.getGravity(), style.getXOffset(), style.getYOffset());

        BaseToast myToast = new BaseToast(application);
        myToast.setComponent(createTextView(application, style));
        myToast.setAlignment(style.getGravity());
        myToast.setOffset(style.getXOffset(), style.getYOffset());
        setToast(myToast);
    }

    /**
     * 显示一个对象的吐司
     *
     * @param object 对象
     */
    public static void show(Object object) {
        show(object != null ? object.toString() : "null");
    }

    /**
     * 显示一个吐司
     *
     * @param id 如果传入的是正确的 string id 就显示对应字符串
     *           如果不是则显示一个整数的string
     */
    public static void show(int id) {
        checkToastState();
        try {
            show(getContext().getString(id));
        } catch (Exception ignored) {
            // 如果这是一个 int 整数
            show(String.valueOf(id));
        }
    }

    /**
     * 显示一个吐司
     *
     * @param id   资源 id
     * @param args 参数集
     */
    public static void show(int id, Object... args) {
        show(getContext().getString(id), args);
    }

    /**
     * 显示一个吐司
     *
     * @param format 原字符串
     * @param args   参数集
     */
    public static void show(String format, Object... args) {
        show(String.format(format, args));
    }

    /**
     * 显示一个吐司
     *
     * @param text 需要显示的文本
     */
    public static synchronized void show(String text) {
        checkToastState();
        if (sInterceptor.intercept(sToast, text)) {
            return;
        }
        sStrategy.show(text);
    }

    //***************************************兼容老的Toast的调用方法 start*************************************

    /**
     * 老的Toast调用方法
     *
     * @param context context
     * @param text    显示的内容
     */
    public static void show(Context context, String text) {
        show(text);
    }

    //***************************************兼容老的Toast的调用方法 end*************************************

    /**
     * 取消吐司的显示
     */
    public static synchronized void cancel() {
        checkToastState();

        sStrategy.cancel();
    }

    /**
     * 设置吐司的位置
     *
     * @param gravity 重心
     * @param xOffset x轴偏移
     * @param yOffset y轴偏移
     */
    private static void setGravity(int gravity, int xOffset, int yOffset) {
        checkToastState();
        sToast.setAlignment(gravity);
//        sToast.setOffset(xOffset, yOffset);
    }


    /**
     * 给当前Toast设置新的布局，具体实现可看{@link BaseToast#setComponent(Component)}
     */
    public static void setView(int id) {
        checkToastState();

        setView(LayoutScatter.getInstance(getContext()).parse(id, null, false));
    }

    public static void setView(Component view) {
        checkToastState();

        // 这个 View 不能为空
        checkNullPointer(view);

        // 当前必须用 Application 的上下文创建的 View，否则可能会导致内存泄露
        Context context = view.getContext();
        if (!(context instanceof AbilityPackage)) {
            throw new IllegalArgumentException("The view must be initialized using the context of the application");
        }

        // 如果吐司已经创建，就重新初始化吐司
        if (sToast != null) {
            // 取消原有吐司的显示
            sToast.cancel();
            sToast.setComponent(view);
        }
    }

    /**
     * 获取当前 Toast 的视图
     */
    @SuppressWarnings("unchecked")
    public static <V extends Component> V getView() {
        checkToastState();

        return (V) sToast.getComponent();
    }

    /**
     * 初始化全局的Toast样式
     *
     * @param style 样式实现类，框架已经实现三种不同的样式
     */
    public static void initStyle(IToastStyle style) {
        checkNullPointer(style);
        // 如果吐司已经创建，就重新初始化吐司
        if (sToast != null) {
            // 取消原有吐司的显示
            sToast.cancel();
            sToast.setComponent(createTextView(getContext(), style));
            sToast.setAlignment(style.getGravity());
//            sToast.setOffset(style.getXOffset(), style.getYOffset());
        }
    }

    /**
     * 设置当前Toast对象
     */
    public static void setToast(ToastDialog toast) {
        checkNullPointer(toast);
        if (sToast != null && toast.getComponent() == null) {
            // 移花接木
            toast.setComponent(sToast.getComponent());
        }

        sToast = toast;
        if (sStrategy != null) {
            sStrategy.bind(sToast);
        }
    }

    /**
     * 设置 Toast 显示策略
     */
    public static void setToastStrategy(IToastStrategy handler) {
        checkNullPointer(handler);
        sStrategy = handler;
        if (sToast != null) {
            sStrategy.bind(sToast);
        }
    }

    /**
     * 设置 Toast 拦截器（可以根据显示的内容决定是否拦截这个Toast）
     * 场景：打印 Toast 内容日志、根据 Toast 内容是否包含敏感字来动态切换其他方式显示（这里可以使用我的另外一套框架 XToast）
     */
    public static void setToastInterceptor(IToastInterceptor interceptor) {
        checkNullPointer(interceptor);
        sInterceptor = interceptor;
    }

    /**
     * 获取当前Toast对象
     */
    public static ToastDialog getToast() {
        return sToast;
    }

    /**
     * 检查吐司状态，如果未初始化请先调用{@link com.wss.common.utils.ToastUtils#init(AbilityPackage)}
     */
    private static void checkToastState() {
        // 吐司工具类还没有被初始化，必须要先调用init方法进行初始化
        if (sToast == null) {
            throw new IllegalStateException("ToastUtils has not been initialized");
        }
    }

    /**
     * 检查对象是否为空
     */
    private static void checkNullPointer(Object object) {
        if (object == null) {
            throw new NullPointerException("are you ok?");
        }
    }

    /**
     * 生成默认的 TextView 对象
     */
    private static Text createTextView(Context context, IToastStyle style) {

        ShapeElement drawable = new ShapeElement();
        // 设置背景色
        drawable.setRgbColor(ColorUtils.colorToRgbColor(style.getBackgroundColor()));
        // 设置圆角大小
        drawable.setCornerRadius(PxUtils.fp2px(style.getCornerRadius()));

        Text textView = new Text(context);
        textView.setTextColor(new Color(style.getTextColor()));
        textView.setTextSize((int) style.getTextSize(), Text.TextSizeType.FP);

        textView.setPadding(PxUtils.vp2px(style.getPaddingStart()),
                PxUtils.vp2px(style.getPaddingTop()),
                PxUtils.vp2px(style.getPaddingEnd()),
                PxUtils.vp2px(style.getPaddingBottom()));

        textView.setLayoutConfig(new ComponentContainer
                .LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT,
                ComponentContainer.LayoutConfig.MATCH_CONTENT));

        // setBackground
        textView.setBackground(drawable);

        // 设置最大显示行数
        if (style.getMaxLines() > 0) {
            textView.setMaxTextLines(style.getMaxLines());
        }

        return textView;
    }

    /**
     * 获取上下文对象
     */
    private static Context getContext() {
        checkToastState();
        return sToast.getComponent().getContext();
    }

    /**
     * TODO 检查通知栏权限有没有开启
     * 参考 SupportCompat 包中的方法： NotificationManagerCompat.from(context).areNotificationsEnabled();
     */
    private static boolean areNotificationsEnabled(Context context) {
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//            NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
//            return manager != null && manager.areNotificationsEnabled();
//        } else {
//            AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
//            ApplicationInfo appInfo = context.getApplicationInfo();
//            String packageName = context.getApplicationContext().getPackageName();
//            int uid = appInfo.uid;
//
//            try {
//                Class<?> appOpsClass = Class.forName(AppOpsManager.class.getName());
//                Method checkOpNoThrowMethod = appOpsClass.getMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE, String.class);
//                Field opPostNotificationValue = appOpsClass.getDeclaredField("OP_POST_NOTIFICATION");
//                int value = Integer.parseInt(String.valueOf(opPostNotificationValue.get(Integer.class)));
//                return ((int) checkOpNoThrowMethod.invoke(appOps, value, uid, packageName) == AppOpsManager.MODE_ALLOWED);
//            } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException
//                    | InvocationTargetException | IllegalAccessException | RuntimeException ignored) {
//                return true;
//            }
//        }
        return false;
    }
}
